﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.IO;
using System.Text;
using Excel;

namespace OrderAggregator.InputFormats.MosMart
{
	/// <summary>
    /// Формат "Магазин MосMарт ..."
	/// </summary>
    public class MosMartFormat : Excel.BaseExcelFormat
	{

        public readonly static MosMartFormat Instance = new MosMartFormat();

        private MosMartFormat()
        {
        }

		/// <summary>
		/// Parse
		/// </summary>
		/// <param name="filePath"></param>
		/// <param name="getStream"></param>
		/// <returns></returns>
		public override BaseOrder Parse(string filePath, Func<System.IO.Stream> getStream)
		{
            if (!string.Equals(System.IO.Path.GetExtension(filePath), dotXLS, StringComparison.InvariantCultureIgnoreCase) &&
                !string.Equals(System.IO.Path.GetExtension(filePath), dotXLSX, StringComparison.InvariantCultureIgnoreCase))
            {
                return null;
            }

            
            if (string.Equals(System.IO.Path.GetExtension(filePath), dotXLS, StringComparison.InvariantCultureIgnoreCase))
            {
                var dataSet = ReadAsDataset(getStream());

                if (dataSet == null || dataSet.Tables.Count == 0)
                {
                    return null;
                }

                var table = dataSet.Tables[0];

                Func<int, Func<int, object>> getRow =
                    (row) =>
                    {
                        if (row >= table.Rows.Count)
                        {
                            return null;
                        }

                        return (col) => table.Rows[row][col];
                    };

                return Parse(getRow);
            }
            else
            {
                Func<int, Func<int, object>> getRow;
                using (var context = ReadXLSXAsDataTable(Path.GetFullPath(filePath), out getRow))
                {
                    return Parse(getRow);
                };
            }

		}

        private BaseOrder Parse(Func<int, Func<int, object>> getRow)
        {

            string number, client;
            DateTime date;
            if (!TryParseNumberAndDateAndClient(getRow, out number, out date, out client))
            {
                return null;
            }


            var order = new BaseOrder();
            order.Id = number;
            order.ReceiveTime = date;
            order.Client = client;

            var orderRows = GetOrderRows(getRow);

            foreach (var orderDataRow in orderRows)
            {
                var orderRow = new BaseOrderRow();
                orderRow.ProductCode = orderDataRow(0).ToString();
                orderRow.ProductName = orderDataRow(2).ToString();
                orderRow.Count = decimal.Parse(orderDataRow(4).ToString(), BaseOrderFormat.RuCulture);

                order.OrderRows.Add(orderRow);
            }
            return order; 
        }

	    private bool TryParseNumberAndDateAndClient(
            Func<int, Func<int, object>> getRow, 
            out string number, out DateTime date, out string client
            )
        {
            number = string.Empty;            
            date = DateTime.MinValue;
            client = string.Empty;

            var header = string.Empty;                                    
            var countField = 0;

            for (var i = 0; countField < 3; i++)
            {
                var row = getRow(i);

                if (row == null)
                {
                    break;
                }

                

                header = row(0) as string;

                var colmn2 = Convert.ToString(row(2));

                if (!string.IsNullOrEmpty(header))
                {

                    if (string.IsNullOrEmpty(number) && header.Contains("Номер заказа на покупку"))
                    {
                        number = colmn2.Trim();
                        countField++;
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(number) && string.IsNullOrEmpty(client) && header.Contains("Заказчик"))
                        {
                            client = colmn2.Trim();
                            countField++;
                        }
                        if (!string.IsNullOrEmpty(number) && !string.IsNullOrEmpty(client) && header.Contains("Дата поставки"))
                        {

                            if (!string.IsNullOrEmpty(colmn2) && !DateTime.TryParse(colmn2, out date))
                            {
                                date = DateTime.FromOADate(double.Parse(colmn2));
                            }
                            countField++;
                        }
                    }
                }
            }

            if (countField < 3)
            {
                return false;
            }
          
            return true;
        }

        private static List<Func<int, object>> GetOrderRows(Func<int, Func<int, object>> getRow)
        {
            var rows = new List<Func<int, object>>();

            int startRow = -1;

            for (int i = 5; ; i++)
            {
                var row = getRow(i);

                if (row == null)
                {
                    break;
                }

                var strColmn1 = row(0) as string;
                var strColmn2 = row(1) as string;

                if (string.Equals(strColmn1, "Код", StringComparison.InvariantCultureIgnoreCase) &&
                    string.Equals(strColmn2, "Штрих-код", StringComparison.InvariantCultureIgnoreCase))
                {
                    startRow = i + 1;
                    break;
                }
            }

            if (startRow < 0)
            {
                return rows;
            }

            for (int i = startRow; ; i++)
            {
                var row = getRow(i);

                if (row == null)
                {
                    break;
                }

                

                var strColmn1 = row(1) as string;

                if (string.IsNullOrEmpty(strColmn1))
                {
                    break;
                }

                rows.Add(row);
            }

            return rows;
        }

       
    }
}
